//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Policy Injection Application Block
//===============================================================================

using System.ComponentModel;
using System.Threading;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
using EntLibContrib.PolicyInjection.CallHandlers.Configuration;

namespace EntLibContrib.PolicyInjection.CallHandlers
{
	/// <summary>
	/// An <see cref="ICallHandler"/> that uses ISynchronizeInvoke to invoke the next handler.
	/// </summary>
	/// <remarks>Only supported for targets implementing ISynchronizeInvoke. Otherwise, the handler will have no effect.</remarks>
	[ConfigurationElementType(typeof(SynchronizedCallHandlerData))]
	public class SynchronizedCallHandler : ICallHandler
	{
		#region Fields
		private int order;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new instance of the <see cref="SynchronizedCallHandler"/> class.
		/// </summary>
		public SynchronizedCallHandler()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SynchronizedCallHandler"/> class.
		/// </summary>
		/// <param name="order">Order in which handler will be executed.</param>
		public SynchronizedCallHandler(int order)
		{
			this.order = order;
		}
		#endregion

		#region ICallHandler Members
		/// <summary>
		/// Processes the method call.
		/// </summary>
		/// <param name="input"><see cref="IMethodInvocation"/> with information about the call.</param>
		/// <param name="getNext">delegate to call to get the next handler in the pipeline.</param>
		/// <returns>Return value from the target.</returns>
		/// <remarks>This handler invokes the call using ISynchronizeInvoke</remarks>
		public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
		{
			IMethodReturn result = null;

			ISynchronizeInvoke synchronizedInvoke = input.Target as ISynchronizeInvoke;

			if (synchronizedInvoke == null || !synchronizedInvoke.InvokeRequired)
			{
				result = getNext()(input, getNext);
			}
			else
			{
				synchronizedInvoke.Invoke(new ThreadStart(delegate()
				{
					result = getNext()(input, getNext);
				}), null);
			}

			return result;
		}

		/// <summary>
		/// Order in which the handler will be executed
		/// </summary>
		/// <value></value>
		public int Order
		{
			get
			{
				return order;
			}
			set
			{
				order = value;
			}
		}
		#endregion
	}
}
